/*
 * Unidata Platform Community Edition
 * Copyright (c) 2013-2020, UNIDATA LLC, All rights reserved.
 * This file is part of the Unidata Platform Community Edition software.
 *
 * Unidata Platform Community Edition is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Unidata Platform Community Edition is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */
package org.unidata.mdm.meta.module;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.unidata.mdm.core.service.MetaModelService;
import org.unidata.mdm.meta.configuration.MetaConfiguration;
import org.unidata.mdm.meta.configuration.MetaConfigurationConstants;
import org.unidata.mdm.meta.configuration.MetaConfigurationProperty;
import org.unidata.mdm.meta.configuration.MetaMessagingDomain;
import org.unidata.mdm.meta.migration.InstallMetaSchemaMigrations;
import org.unidata.mdm.meta.migration.UninstallMetaSchemaMigrations;
import org.unidata.mdm.meta.util.ValueGeneratingUtils;
import org.unidata.mdm.system.context.DatabaseMigrationContext;
import org.unidata.mdm.system.service.DatabaseMigrationService;
import org.unidata.mdm.system.service.PlatformConfiguration;
import org.unidata.mdm.system.type.configuration.ConfigurationProperty;
import org.unidata.mdm.system.type.messaging.DomainType;
import org.unidata.mdm.system.type.module.AbstractModule;
import org.unidata.mdm.system.type.module.Dependency;
import org.unidata.mdm.system.type.module.ImportableExportable;
import org.unidata.mdm.system.type.pipeline.Segment;
import org.unidata.mdm.system.util.DataSourceUtils;

import javax.sql.DataSource;
import java.util.Collection;
import java.util.Set;

public class MetaModule extends AbstractModule implements ImportableExportable {

    private static final Logger LOGGER = LoggerFactory.getLogger(MetaModule.class);

    public static final String MODULE_ID = "org.unidata.mdm.meta";

    private static final Set<Dependency> DEPENDENCIES = Set.of(
            new Dependency("org.unidata.mdm.core", "6.0"),
            new Dependency("org.unidata.mdm.draft", "6.0")
    );

    @Autowired
    private MetaModelService metaModelService;

    @Autowired
    private DataSource metaDataSource;

    @Autowired
    private MetaConfiguration configuration;

    @Autowired
    private DatabaseMigrationService migrationService;

    @Autowired
    private PlatformConfiguration platformConfiguration;

    private boolean install;

    @Override
    public String getId() {
        return MODULE_ID;
    }

    @Override
    public String getVersion() {
        return "6.0";
    }

    @Override
    public String getName() {
        return "Unidata Meta module";
    }

    @Override
    public String getDescription() {
        return "Meta";
    }

    @Override
    public Collection<Dependency> getDependencies() {
        return DEPENDENCIES;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public DomainType[] getMessagingDomains() {
        return new DomainType[] { MetaMessagingDomain.DOMAIN };
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String[] getResourceBundleBasenames() {
        return new String[]{ "meta_messages" };
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ConfigurationProperty<?>[] getConfigurationProperties() {
        return MetaConfigurationProperty.values();
    }

    @Override
    public void install() {
        LOGGER.info("Install");

        migrate();
        install = true;
    }

    @Override
    public void uninstall() {
        LOGGER.info("Uninstall");
        migrationService.migrate(DatabaseMigrationContext.builder()
                .schemaName(MetaConfigurationConstants.META_SCHEMA_NAME)
                .logName(MetaConfigurationConstants.META_MIGRATION_LOG_NAME)
                .dataSource(metaDataSource)
                .migrations(UninstallMetaSchemaMigrations.migrations())
                .build());
    }

    @Override
    public void start() {

        LOGGER.info("Starting...");

        // Utils and indexes
        ValueGeneratingUtils.init();

        if (platformConfiguration.isDeveloperMode() && !install) {
            migrate();
        }

        // Publish segments
        addSegments(configuration.getBeansOfType(Segment.class).values());

        LOGGER.info("Started.");
    }

    @Override
    public void stop() {
        LOGGER.info("Stopping...");
        metaModelService.shutdown();
        DataSourceUtils.shutdown(metaDataSource);
        LOGGER.info("Stopped.");
    }

    private void migrate() {
        migrationService.migrate(DatabaseMigrationContext.builder()
                .schemaName(MetaConfigurationConstants.META_SCHEMA_NAME)
                .logName(MetaConfigurationConstants.META_MIGRATION_LOG_NAME)
                .dataSource(metaDataSource)
                .migrations(InstallMetaSchemaMigrations.migrations())
                .build());
    }
}
